/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
  url = url == null ? window.location.href : url;
  const search = url.substring(url.lastIndexOf("?") + 1);
  const obj = {};
  const reg = /([^?&=]+)=([^?&=]*)/g;
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1);
    let val = decodeURIComponent($2);
    val = String(val);
    obj[name] = val;
    return rs;
  });
  return obj;
}

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
  // returns the byte length of an utf8 string
  let s = str.length;
  for (let i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) s++;
    else if (code > 0x7ff && code <= 0xffff) s += 2;
    if (code >= 0xdc00 && code <= 0xdfff) i--;
  }
  return s;
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = [];
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i]);
    }
  }
  return newArray;
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
  if (!json) return "";
  return cleanArray(
    Object.keys(json).map((key) => {
      if (json[key] === undefined) return "";
      return encodeURIComponent(key) + "=" + encodeURIComponent(json[key]);
    })
  ).join("&");
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = url.split("?")[1];
  if (!search) {
    return {};
  }
  return JSON.parse(
    '{"' +
    decodeURIComponent(search)
      .replace(/"/g, '\\"')
      .replace(/&/g, '","')
      .replace(/=/g, '":"')
      .replace(/\+/g, " ") +
    '"}'
  );
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement("div");
  div.innerHTML = val;
  return div.textMainContent || div.innerText;
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== "object") {
    target = {};
  }
  if (Array.isArray(source)) {
    return source.slice();
  }
  Object.keys(source).forEach((property) => {
    const sourceProperty = source[property];
    if (typeof sourceProperty === "object") {
      target[property] = objectMerge(target[property], sourceProperty);
    } else {
      target[property] = sourceProperty;
    }
  });
  return target;
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return;
  }
  let classString = element.className;
  const nameIndex = classString.indexOf(className);
  if (nameIndex === -1) {
    classString += "" + className;
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length);
  }
  element.className = classString;
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result;

  const later = function () {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp;
    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };

  return function (...args) {
    // eslint-disable-next-line
    context = this;
    timestamp = +new Date();
    const callNow = immediate && !timeout;
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }

    return result;
  };
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== "object") {
    throw new Error("error arguments", "deepClone");
  }
  const targetObj = source.constructor === Array ? [] : {};
  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === "object") {
      targetObj[keys] = deepClone(source[keys]);
    } else {
      targetObj[keys] = source[keys];
    }
  });
  return targetObj;
}

/**
 * 将data的值赋到params中
 * @param {Objct} params 被赋值
 * @param {Objct} data 原对象,用于给params赋值
 * @param {Function} callback 回调函数
 */
export function MergeData(params, data, callback) {
  let state = true;
  for (const key in params) {
    state = true;
    if (data[key] === undefined) continue;
    if (typeof callback === "function") {
      state = callback(data[key], key, params);
    }
    // 默认保存data的值到params,替换原来params[key]值
    // 如果不保存data的值到params, callback回调函数返回false
    if (state !== false) {
      params[key] = data[key];
    }
  }
}

/**
 * 数组去重
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr));
}

/**
 * 数组对象根据对象中指定的属性去重
 * @param {Array<Object>} arr
 * @param {String} u_key 对象的属性
 * @returns {Array}
 */
export function uniqueArrObj(arr, u_key) {
  let map = new Map();
  arr.forEach((item) => {
    if (!map.has(item[u_key])) {
      map.set(item[u_key], item);
    }
  });
  return [...map.values()];
}

/**
 * @returns {string}
 */

/**
 * 获取字符长度 中文2 英文1
 */
export function gbLen(str) {
  let len = 0;
  for (let i = 0; i < str.length; i++) {
    if (
      str.charCodeAt(i) < 65 ||
      str.charCodeAt(i) > 122 ||
      (str.charCodeAt(i) >= 91 && str.charCodeAt(i) <= 96)
    ) {
      len += 2;
    } else {
      len++;
    }
  }
  return len;
}

/*
 * 下划线转驼峰
 * */
export function toHump(name) {
  // eslint-disable-next-line no-useless-escape
  return name.replace(/\_(\w)/g, function (all, letter) {
    return letter.toUpperCase();
  });
}

/**
 * el-tree子节点全选只获取父节点
 */
export function getSimpleCheckedNodes(store) {
  const checkedNodes = [];
  const traverse = function (node) {
    const childNodes = node.root ? node.root.childNodes : node.childNodes;

    childNodes.forEach((child) => {
      if (child.checked) {
        checkedNodes.push(child.data);
      }
      if (child.indeterminate) {
        traverse(child);
      }
    });
  };
  traverse(store);
  return checkedNodes;
}
/**
 * 根据url 下载图片
 * @param {String} imgsrc 下载图片地址
 * @param {String} name 图片名
 */
export function downloadIamge(imgsrc, name) {
  let image = new Image();
  // 解决跨域 Canvas 污染问题
  image.setAttribute("crossOrigin", "anonymous");
  image.onload = function () {
    let canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;
    let context = canvas.getContext("2d");
    context.drawImage(image, 0, 0, image.width, image.height);
    let url = canvas.toDataURL("image/png"); // 得到图片的base64编码数据
    let a = document.createElement("a"); // 生成一个a元素
    let event = new MouseEvent("click"); // 创建一个单击事件
    a.download = name || "photo"; // 设置图片名称
    a.href = url; // 将生成的URL设置为a.href属性
    a.dispatchEvent(event); // 触发a的单击事件
  };
  image.src = imgsrc;
}

/**
 * 根据url导出
 * @param {String} url 下载地址
 */
export function exportFuc(url) {
  // 创建一个 form
  let form1 = document.createElement("form");
  form1.id = "form1";
  form1.name = "form1";

  // 添加到 body 中
  document.body.appendChild(form1);
  // form 的提交方式
  form1.method = "GET";
  // form 提交路径
  form1.action = url;

  // 对该 form 执行提交
  form1.submit();
  // 删除该 form
  document.body.removeChild(form1);
}

/**
 * @description: 根据后缀判断文件类型
 * @param {String} fileName  文件名称
 * @return {String}  文件类型
 */
export function getFileType(fileName) {
  // 后缀获取
  let suffix = "";
  // 获取类型结果
  let result = "";
  try {
    const flieArr = fileName.split(".");
    suffix = flieArr[flieArr.length - 1];
  } catch (err) {
    suffix = "";
  }
  // fileName无后缀返回 false
  if (!suffix) {
    return false;
  }
  suffix = suffix.toLocaleLowerCase();
  // 图片格式
  const imglist = ["png", "jpg", "jpeg", "bmp", "gif"];
  // 进行图片匹配
  result = imglist.find((item) => item === suffix);
  if (result) {
    return "image";
  }
  // 匹配txt
  const txtlist = ["txt"];
  result = txtlist.find((item) => item === suffix);
  if (result) {
    return "txt";
  }
  // 匹配 excel
  const excelist = ["xls", "xlsx"];
  result = excelist.find((item) => item === suffix);
  if (result) {
    return "excel";
  }
  // 匹配 word
  const wordlist = ["doc", "docx"];
  result = wordlist.find((item) => item === suffix);
  if (result) {
    return "word";
  }
  // 匹配 pdf
  const pdflist = ["pdf"];
  result = pdflist.find((item) => item === suffix);
  if (result) {
    return "pdf";
  }
  // 匹配 ppt
  const pptlist = ["ppt", "pptx"];
  result = pptlist.find((item) => item === suffix);
  if (result) {
    return "ppt";
  }
  // 匹配 视频
  const videolist = [
    "mp4",
    "m2v",
    "mkv",
    "rmvb",
    "wmv",
    "avi",
    "flv",
    "mov",
    "m4v",
  ];
  result = videolist.find((item) => item === suffix);
  if (result) {
    return "video";
  }
  // 匹配 音频
  const radiolist = ["mp3", "wav", "wmv"];
  result = radiolist.find((item) => item === suffix);
  if (result) {
    return "radio";
  }
  // 匹配 压缩包
  const rarlist = ["rar", "zip", "jar", "7z"];
  result = rarlist.find((item) => item === suffix);
  if (result) {
    return "rar";
  }
  // 匹配 网页
  const htmllist = ["htm", "html", "jsp", "asp", "shtml", "nsp", "php"];
  result = htmllist.find((item) => item === suffix);
  if (result) {
    return "html";
  }
  // 匹配 exe
  const exelist = ["exe"];
  result = exelist.find((item) => item === suffix);
  if (result) {
    return "exe";
  }
  // 匹配 psd
  const psdlist = ["psd"];
  result = psdlist.find((item) => item === suffix);
  if (result) {
    return "psd";
  }
  // 匹配 cad
  const cadlist = ["dwg"];
  result = cadlist.find((item) => item === suffix);
  if (result) {
    return "cad";
  }
  // 匹配 镜像文件
  const isolist = [
    "iso",
    "bin",
    "nrg",
    "vsd",
    "cif",
    "fcd",
    "img",
    "ccd",
    "c2d",
    "dfi",
    "tao",
    "dao",
    "cue",
  ];
  result = isolist.find((item) => item === suffix);
  if (result) {
    return "iso";
  }
  // 其他 文件类型
  return "other";
}

/**
 * 文件导出
 */
export function downloadFile(src) {
  let iframe = document.createElement("iframe");
  iframe.src = src;
  iframe.style.display = "none";
  const timer = setInterval(function () {
    let iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
    // Check if loading is complete
    if (
      iframeDoc.readyState == "complete" ||
      iframeDoc.readyState == "interactive"
    ) {
      iframe.remove();
      clearInterval(timer);
    }
  }, 500);
  document.body.appendChild(iframe);
}

/**
 * 根据数组某个字段升序排列
 * @param {} key
 * @returns
 */
export function toSort(arr, key, type) {
  arr.sort((value1, value2) => {
    let val1 = value1[key];
    let val2 = value2[key];
    // 降序
    if (type == "down") {
      return val2 - val1;
    }
    // 升序
    return val1 - val2;
  });
}
//添加按钮权限

export function treeTolistTree(arr) {
  let res = [];
  !(function fn(arr) {
    arr.forEach(function (item) {
      res.push(item);
      if (item.children && item.children.length > 0) {
        fn(item.children);
      }
    });
  })(arr);
  return res;
}

//添加按钮权限
export function addBtnPermission(treelist, name) {
  const menuList = treeTolistTree(treelist);
  let btnList = [];
  menuList.forEach((i) => {
    if (i.type === "BUTTON") {
      btnList.push(i.frontId);
    }
  });
  localStorage.setItem(name, JSON.stringify(btnList));
}
/**
 *  数据去抖
 */
export function debounceUtils(func, delay) {
  let timer;
  return function (...args) {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}

// 把分换算成元 单位自己写
export function setMoneyConfig(payOfMoney) {
  if (payOfMoney) {
    let price = "";
    if (payOfMoney < 10) {
      price = `00${payOfMoney}`;
    } else if (payOfMoney >= 10 && payOfMoney < 100) {
      price = `0${payOfMoney}`;
    } else {
      price = `${payOfMoney}`;
    }

    if (price) {
      return `${price.slice(0, price.length - 2)}.${price.slice(-2)}元`;
    }
  } else {
    return 0 + '元';
  }
}

// 条件选择数据结构

export function conditionalOriginal(item, type) {
  return {
    joinOperator: "And",
    children: [
      {
        joinOperator: "And",
        children: [
          {
            joinOperator: "And",
            children: [
              {
                expression: "",
                joinOperator: "And",
                eventValue: type || "",
                propertyType: item?.propertyType || "",
                propertyKey: item?.propertyKey || "",
                relation: "",
                value: "",
              },
            ],
          },
        ],
      },
    ],
  };
}

// 生成随机id
export const newRandomUid = () => {
  return Math.random().toString(36).substr(3, 10);
};

//类型对应的表达式
export function connectionsData() {
  return {
    "-1": {
      list: [
        { name: "=", id: "==" },
        { name: "≠", id: "!=" },
        { name: "包含", id: "true" },
      ],
      initialValue: "", // 数据的初始值
    },
    0: {
      list: [
        { name: "=", id: "==" },
        { name: "≠", id: "!=" },
        { name: ">", id: ">" },
        { name: "<", id: "<" },
        { name: "≥", id: ">=" },
        { name: "≤", id: "<=" },
      ],
      initialValue: 1, // 数据的初始值
    },
    1: {
      list: [
        { name: "=", id: "==" },
        { name: "≠", id: "!=" },
        { name: "包含", id: "true" },
      ],
      initialValue: "",
    },
    2: {
      list: [
        { name: "=", id: "==" },
        { name: "≠", id: "!=" },
        { name: ">", id: ">" },
        { name: "<", id: "<" },
        { name: "≥", id: ">=" },
        { name: "≤", id: "<=" },
        { name: "属于", id: "true" },
      ],
      initialValue: "0", // 数据的初始值
    },
    3: {
      list: [
        { name: "=", id: "==" },
        { name: "≠", id: "!=" },
        { name: ">", id: ">" },
        { name: "<", id: "<" },
        { name: "≥", id: ">=" },
        { name: "≤", id: "<=" },
        { name: "属于", id: "true" },
      ],
      initialValue: "0", // 数据的初始值
    },
    4: {
      list: [
        { name: "=", id: "==" },
        { name: "≠", id: "!=" },
        { name: "包含", id: "true" },
      ],
      initialValue: "", // 数据的初始值
    },
    // 5: {
    //   list: [
    //     { name: "是", id: "true" },
    //     { name: "否", id: "false" },
    //   ],
    //   initialValue: "true", // 数据的初始值
    // },
    externa: [
      { name: "=", id: "eq" },
      { name: "≠", id: "ne" },
      { name: ">", id: "gt" },
      { name: "<", id: "lt" },
      { name: "≥", id: "ge" },
      { name: "≤", id: "le" },
    ]
  }
}

// 时间转换时间戳
export function formatTimeStamp(val) {
  if (val) {
    return new Date(val).getTime()
  }
  return ""
}
// 时间戳转日期
export function timestampToTime(timestamp) {
  let date = new Date(timestamp);//时间戳为10位需*1000，时间戳为13位的话不需乘1000
  let Y = date.getFullYear() + '-';
  let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
  let D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';
  let h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
  let m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
  let s = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
  return Y + M + D + h + m + s;
}

// 时间转换毫秒数
export function formatTimeMs(num, type) {
  // num是数量  type是类型 1：天， 2： 时， 3：分
  let ms = ""
  if (type == 1) {
    ms = 60 * 60 * 24 * 1000 * num
  } else if (type == 2) {
    ms = 60 * 60 * 1000 * num
  } else if (type == 3) {
    ms = 60 * 1000 * num
  }
  return ms
}

/**
 * 传入你所要转换的阿拉伯数字 123 => 一百二十三
 * console.log(toChineseNumber(1))
 * @param n
 * @returns {string}
 */
export function toChineseNumber(n) {
  if (!Number.isInteger(n) && n < 0) {
    throw Error('请输入自然数');
  }
  const digits = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
  const positions = ['', '十', '百', '千', '万', '十万', '百万', '千万', '亿', '十亿', '百亿', '千亿'];
  const charArray = String(n).split('');
  let result = '';
  let prevIsZero = false;
  //处理0  deal zero
  for (let i = 0; i < charArray.length; i++) {
    const ch = charArray[i];
    if (ch !== '0' && !prevIsZero) {
      result += digits[parseInt(ch)] + positions[charArray.length - i - 1];
    } else if (ch === '0') {
      prevIsZero = true;
    } else if (ch !== '0' && prevIsZero) {
      result += '零' + digits[parseInt(ch)] + positions[charArray.length - i - 1];
    }
  }
  //处理十 deal ten
  if (n < 100) {
    result = result.replace('一十', '十');
  }
  return result;
}

export function fileDownload(url, name) {
  let a = document.createElement("a");
  a.href = url
  a.download = name
  document.body.appendChild(a);
  // 点击下载
  a.click();
  document.body.removeChild(a);
}

// 规则引擎组件统一配置
const limitCompontentList = [
  'timeLimit',
  'groupLimit',
  'tagLimit',
  'activityLimit',
  'vipLimit',
  'ipStrategyLimit',
  'ipNumber',
  'phoneStrategyLimit',
  'phoneNumber',
  'externalLimit',
]

// 设置规则引擎组件的引用
export function setLimitCompontentList(arr) {
  if (arr) {
    return arr
  } else {
    return limitCompontentList
  }
}

/**
 * 根据后缀获取 MIME 类型
 * @param { string } suffix 文件后缀
 * @returns {string} mime类型字符串
 */
export function getMIMEBySuffix(suffix) {
  let _suffix = suffix.toLowerCase();

  if (!_suffix) {
    return "application/octet-stream;";
  }
  if (_suffix === "gif") {
    return "image/gif;";
  }
  if (_suffix === "jpg") {
    return "image/jpeg;";
  }
  if (_suffix === "jpeg") {
    return "image/jpeg;";
  }
  if (_suffix === "png") {
    return "image/png;";
  }
  if (_suffix === "pdf") {
    return "application/pdf;";
  }
  if (_suffix === "doc") {
    return "application/msword;";
  }
  if (_suffix === "docx") {
    return "application/vnd.openxmlformats-officedocument.wordprocessingml.document;";
  }
  if (_suffix === "xls") {
    return "application/vnd.ms-excel;";
  }
  if (_suffix === "xlsx") {
    return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;";
  }
  if (_suffix === "ppt") {
    return "application/vnd.ms-powerpoint;";
  }
  if (_suffix === "pptx") {
    return "application/vnd.openxmlformats-officedocument.presentationml.template;";
  }
  return "application/octet-stream;";
}


/**
 * 获取  xx积分 + xx元 | xx积分 | xx元 形式的 字符串
 * @param { Object | undefined } targetObj 要自动取值的目标对象
 * @param { Object } [options] 选项
 * @param { string } [options.pointsValue] 积分值 指定此项时，会跳过key的检查
 * @param { string } [options.pointsKey] target中指定的积分key，指定此项时，避免从预设的key中查找
 * @param { string } [options.pointsUnitValue] target中指定的积分单位 不指定则从options.pointsUnitKey 中查找
 * @param { string } [options.pointsUnitKey] target中指定的积分单位Key target中指定的积分单位key 不指定则为“积分”
 * @param { string } [options.moneyValue] 值为分，会转成元
 * @param { string } [options.moneyKey]
 * @param { boolean } [options.onlyPoints] 仅返回积分
 * @param { boolean } [options.onlyMoney] 仅返回金额
 * @returns { string } xx积分 + xx元 | xx积分 | xx元
 */
export function getPointsAndMoneyString(
  targetObj,
  options = {
    pointsValue: undefined,
    pointsKey: undefined,
    pointsUnitValue: undefined,
    pointsUnitKey: undefined,
    moneyKey: undefined,
    moneyValue: undefined,
    onlyPoints: false,
    onlyMoney: false,
    separator: ' + ',
  }
) {
  if (!targetObj) {
    return ''
  }
  
  const isEmpty = (val) => val === undefined || val === null || val === ''

  // 后端返回的对象中 可能出现的积分key，如果options中未指定，就从这里按序查找
  const pointsProbablyKeys = ['payOfCurrencyCount'];  // 可以添加更多

  // 积分数值
  let _pointsValue = options.pointsValue;

  if (isEmpty(_pointsValue)) {
    let _pointsKey = '';
    if (options.pointsKey) {
      _pointsKey = options.pointsKey
    } else {
      _pointsKey = Object.keys(targetObj).find(key => pointsProbablyKeys.includes(key))
    }

    if (_pointsKey) {
      _pointsValue = targetObj[_pointsKey]
    }
  }

  // 积分单位
  let _pointsUnit = options.pointsValue ?? null;

  if (!_pointsUnit) {
    if (options.pointsUnitKey) {
      _pointsUnit = targetObj[options.pointsUnitKey]
    } else {
      _pointsUnit = '积分'
    }
  }

  // 积分最终字符串
  const pointsPart = _pointsValue + _pointsUnit

  // 后端返回的对象中 可能出现的金额key
  const moneyProbablyKeys = ['payOfMoney']; // 可以添加更多

  // 金额数值
  let _moneyValue = options.moneyValue;

  if (isEmpty(_moneyValue)) {
    let _moneyKey = '';
    if (options.moneyKey) {
      _moneyKey = options.moneyKey
    } else {
      _moneyKey = Object.keys(targetObj).find(key => moneyProbablyKeys.includes(key))
    }

    if (_moneyKey) {
      _moneyValue = targetObj[_moneyKey]
    }
  }

  const moneyUnit = '元'
  let moneyPart = ''
  // 后端默认为分
  if (!isEmpty(_moneyValue)) {
    _moneyValue = (_moneyValue / 100).toFixed(2);
    moneyPart = (_moneyValue ?? '') + moneyUnit
  }

  let combinedString = ''
  if (!isEmpty(_pointsValue) && !isEmpty(_moneyValue)) {
    combinedString += pointsPart
    combinedString += options.separator
    combinedString += moneyPart
  } else if (!isEmpty(_pointsValue) && isEmpty(_moneyValue)) {
    combinedString += pointsPart
  } else {
    combinedString += moneyPart
  }

  if (options.onlyPoints) {
    return pointsPart
  } else if (options.onlyMoney) {
    return moneyPart
  } else {
    return combinedString
  }
}
